﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace ETask.Client.ViewModels
{
    public class RelayCommand<T> : ICommand
    {
        private readonly Action<T> _execute;
        private readonly Func<T, bool> _canExecute;

        /// <summary>
        /// 当命令可执行状态改变时触发
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="execute">命令执行的方法</param>
        /// <param name="canExecute">判断命令是否可执行的方法（可选）</param>
        public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        /// <summary>
        /// 判断命令是否可执行
        /// </summary>
        public bool CanExecute(object parameter)
        {
            // 处理参数类型转换
            if (parameter is T tParam)
            {
                return _canExecute?.Invoke(tParam) ?? true;
            }

            // 参数类型不匹配时，检查是否允许 null
            if (parameter == null && typeof(T).IsClass)
            {
                return _canExecute?.Invoke(default) ?? true;
            }

            return false;
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        public void Execute(object parameter)
        {
            if (parameter is T tParam)
            {
                _execute(tParam);
            }
            // 处理参数为 null 的情况（当 T 是引用类型时）
            else if (parameter == null && typeof(T).IsClass)
            {
                _execute(default);
            }
        }
    }

    // 非泛型版本，方便不需要参数的场景
    public class RelayCommand : RelayCommand<object>
    {
        public RelayCommand(Action execute, Func<bool> canExecute = null)
            : base(_ => execute(), canExecute != null ? (_ => canExecute()) : null)
        {
        }
    }
}
